/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.jxtafileshare;

import net.jxta.document.MimeMediaType;
import net.jxta.endpoint.ByteArrayMessageElement;
import net.jxta.endpoint.Message;
import net.jxta.endpoint.Message.ElementIterator;
import net.jxta.endpoint.MessageElement;
import net.jxta.endpoint.StringMessageElement;
import net.jxta.endpoint.WireFormatMessage;
import net.jxta.endpoint.WireFormatMessageFactory;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
/**
 * This class manipulates JXTA messages to add and
 * read different message elements
 */
public class Messages {
    private final static MimeMediaType GZIP_MEDIA_TYPE =
            new MimeMediaType("application/gzip").intern();

    /**
     * Adds a string to a message as a StringMessageElement
     */
    public static void addStringToMessage(Message message,
            String nameSpace, String elemName, String string) {
        message.addMessageElement(nameSpace,
                new StringMessageElement(elemName,
                string, null));
    }

    /**
     * Adds a long to a message
     */
    public static void addLongToMessage(Message message,
            String nameSpace, String elemName, long data) {
        message.addMessageElement(nameSpace,
                new StringMessageElement(elemName,
                Long.toString(data), null));
    }

    /**
     * Adds an int to a message
     */
    public static void addIntegerToMessage(Message message,
            String nameSpace, String elemName, int data) {
        message.addMessageElement(nameSpace,
                new StringMessageElement(elemName,
                Integer.toString(data), null));
    }

    /**
     * Adds a byte array to a message
     */
    public static void addByteArrayToMessage(Message message, String nameSpace,
            String elemName, byte[] data, boolean compress) throws IOException {
        byte[] buffer = data;
        MimeMediaType mimeType = MimeMediaType.AOS;
        if(compress) {
            ByteArrayOutputStream outStream = new ByteArrayOutputStream();
            GZIPOutputStream gos = new GZIPOutputStream(outStream);
            gos.write(data, 0, data.length);
            gos.finish();
            gos.close();
            buffer = outStream.toByteArray();
            mimeType = GZIP_MEDIA_TYPE;
        }
        message.addMessageElement(nameSpace,
                new ByteArrayMessageElement(elemName,
                mimeType, buffer, null));
    }

    /**
     * Ads an object to message within the specified name
     * space and with the specified element name
     */
    public static void addObjectToMessage(Message message, String nameSpace,
            String elemName, Object object) throws IOException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);

        oos.writeObject(object);
        oos.close();
        bos.close();
        addByteArrayToMessage(message, nameSpace, elemName, bos.toByteArray(), false);
    }

    /**
     * Returns a string from a message
     */
    public static String getStringFromMessage(Message message,
            String nameSpace, String elemName) {
        MessageElement me = message.getMessageElement(nameSpace, elemName);

        if(null != me) {
            return me.toString();
        } else {
            return null;
        }
    }

    /**
     * Returns a Long from a message
     */
    public static long getLongFromMessage(Message message,
            String nameSpace, String elemName) throws NumberFormatException {
        String longStr = getStringFromMessage(message, nameSpace, elemName);
        if(null != longStr) {
            return Long.parseLong(longStr);
        } else {
            throw new NumberFormatException("No such Message Element.");
        }
    }

    public static int getIntegerFromMessage(Message message,
            String nameSpace, String elemName) throws NumberFormatException {
        String intStr = getStringFromMessage(message, nameSpace, elemName);

        if(null != intStr) {
            return Integer.parseInt(intStr);
        } else {
            throw new NumberFormatException("No such Message Element.");
        }
    }

    /**
     * Returns an input stream for a byte array
     */
    public static InputStream getInputStreamFromMessage(Message message,
            String nameSpace, String elemName) throws IOException {
        InputStream result = null;
        MessageElement element = message.getMessageElement(nameSpace, elemName);

        if(null == element) {
            return null;
        }

        if(element.getMimeType().equals(GZIP_MEDIA_TYPE)) {
            result = new GZIPInputStream(element.getStream());
        } else if(element.getMimeType().equals(MimeMediaType.AOS)) {
            result = element.getStream();
        }
        return result;
    }

    /**
     * Reads a single Java Object from a message
     */
    public static Object getObjectFromMessage(Message message, String nameSpace,
            String elemName) throws IOException, ClassNotFoundException {
        InputStream is = getInputStreamFromMessage(message, nameSpace, elemName);

        if(null == is) {
            return null;
        }
        ObjectInputStream ois = new ObjectInputStream(is);
        return ois.readObject();
    }

    /**
     * Prints message element names and content and some stats
     */
    public static void printMessageStats(Message msg, boolean verbose) {
        try {
            System.out.println("-------------------Begin Message-----------------");
            WireFormatMessage serialed = WireFormatMessageFactory.toWire(msg,
                    new MimeMediaType("application/x-jxta-msg"), null);
            System.out.println("Message Size: " + serialed.getByteLength());

            ElementIterator it = msg.getMessageElements();
            while(it.hasNext()) {
                MessageElement el = it.next();
                System.out.println("Element: " + it.getNamespace() + " :: " +
                        el.getElementName());
                if(verbose) {
                    System.out.println("[" + el + "]");
                }
            }
            System.out.println("-------------------End Message-------------------");
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}
